const fs = require('fs');
const {fromRoot} = require("../utils/path");

function fromDCloudIO(path) {
  return fromRoot('node_modules/@dcloudio', path)
}

function replaceAll(content = '', a, b) {
  if (content.replaceAll) {
    return content.replaceAll(a, b)
  }

  while (content.includes(a)) {
    content = content.replace(a, b);
  }

  return content;
}

function replacesAll(content, pairs = []) {
  pairs.forEach((item) => {
    const [a, b] = item;
    content = replaceAll(content, a, b);
  })
  return content;
}

function resetPlugin() {
  const pluginIndexDTSPath = fromDCloudIO("vite-plugin-uni/dist/index.d.ts");
  const pluginIndexJSPath = fromDCloudIO("vite-plugin-uni/dist/index.js");

  const dts = fs.readFileSync(pluginIndexDTSPath).toString();
  const js = fs.readFileSync(pluginIndexJSPath).toString();

  if (dts.includes('default function uniPlugin')) {
    fs.writeFileSync(pluginIndexDTSPath, dts.replace('default function uniPlugin', 'function uni'));
    console.log('已修正 @dcloudio/vite-plugin-uni 声明文件');
  }

  if (js.includes('exports.default = uniPlugin')) {
    fs.writeFileSync(pluginIndexJSPath, js.replace('exports.default = uniPlugin', 'exports.uni = uniPlugin'));
    console.log('已修正 @dcloudio/vite-plugin-uni js文件');
  }
}

function injectAction() {
  const fromPath = fromRoot('scripts/assets/resetPagesJsonPath.js');
  const toPath = fromDCloudIO('vite-plugin-uni/dist/cli/resetPagesJsonPath.js')
  if (!fs.existsSync(toPath)) {
    fs.copyFileSync(fromPath, toPath);
    console.log('已将 resetPagesJsonPath.js 复制到 @dcloudio/vite-plugin-uni/dist/cli');
  }

  const actionPath = fromRoot('node_modules/@dcloudio/vite-plugin-uni/dist/cli/action.js');
  const actionStr = fs.readFileSync(actionPath).toString();

  if (!actionStr.includes('resetPagesJsonPath')) {
    fs.writeFileSync(
      actionPath,
      replacesAll(actionStr, [
        [
          'const shared_1 = require("@vue/shared");',
          `const shared_1 = require("@vue/shared");
const {resetPagesJsonPath} = require('./resetPagesJsonPath');`
        ],
        [
          'async function runDev(options) {',
          `async function runDev(options) {
    await resetPagesJsonPath();`
        ],
        [
          'async function runBuild(options) {',
          `async function runBuild(options) {
    await resetPagesJsonPath();`
        ]
      ])
    );
    console.log('已使 uni 支持项目选择、运行环境选择');
  }
}

function resetBuild() {
  const buildPath = fromDCloudIO('vite-plugin-uni/dist/cli/build.js')
  let content = fs.readFileSync(buildPath).toString()
  if (!content.includes('CURRENT_PROJECT')) {
    content = replacesAll(
      content,
      [
        [
          `async function build(options) {`,
          `async function build(options) {
    if (process.env.CURRENT_ENV) options.outDir = path_1.default.join(process.env.UNI_OUTPUT_DIR, process.env.CURRENT_ENV, process.env.CURRENT_PROJECT)
    else options.outDir = path_1.default.join(process.env.UNI_OUTPUT_DIR, process.env.CURRENT_PROJECT)
    process.env.UNI_OUTPUT_DIR = options.outDir`
        ],
        [
          `async function buildSSR(options) {`,
          `async function buildSSR(options) {
    if (process.env.CURRENT_ENV) options.outDir = path_1.default.join(process.env.UNI_OUTPUT_DIR, process.env.CURRENT_ENV, process.env.CURRENT_PROJECT)
    else options.outDir = path_1.default.join(process.env.UNI_OUTPUT_DIR, process.env.CURRENT_PROJECT)
    process.env.UNI_OUTPUT_DIR = options.outDir`
        ]
      ]
    )
    fs.writeFileSync(buildPath, content);
    console.log('已调整dist打包目录，使其支持按项目打包');
  }
}

function resetNormalizePagePath() {
  const filePath = fromDCloudIO('uni-cli-shared/dist/utils.js');
  let content = fs.readFileSync(filePath).toString()

  if (!content.includes('CURRENT_PROJECT')) {
    content = replacesAll(
      content,
      [
        [
          `function normalizePagePath(pagePath, platform) {`,
          `function normalizePagePath(pagePath, platform) {
    let testPagePath = pagePath
    if (process.env.CURRENT_PROJECT && !isStartsWithProject(pagePath)) {
        testPagePath = joinProjectPath(pagePath);
    }`
        ],
        [
          `const absolutePagePath = path_1.default.resolve(process.env.UNI_INPUT_DIR, pagePath)`,
          `const absolutePagePath = path_1.default.resolve(process.env.UNI_INPUT_DIR, testPagePath)`
        ],
        [
          `exports.normalizePath = normalizePath;`,
          `exports.normalizePath = normalizePath;
function isStartsWithProject(path) {
    return path.startsWith(\`projects/\${process.env.CURRENT_PROJECT}\`);
}
exports.isStartsWithProject = isStartsWithProject;
function joinProjectPath(path) {
    return ['projects', process.env.CURRENT_PROJECT, path].join('/');
}
exports.joinProjectPath = joinProjectPath;
function normalizePagesJson2(jsonStr) {
    if (process.env.CURRENT_PROJECT) {
        function checkAndReplace(item, key) {
          if (item[key] && !isStartsWithProject(item[key])) {
              item[key]= joinProjectPath(item[key])
          }
        }
        const json = JSON.parse(jsonStr);
        json.pages = json.pages.map(item => {
            checkAndReplace(item, 'path');
            return item;
        });
        if (json.subPackages) {
            json.subPackages = json.subPackages.map(item => {
                checkAndReplace(item, 'root');
                return item;
            })
        }
        if (json.condition && json.condition.list) {
            json.condition.list = json.condition.list.map(item => {
                checkAndReplace(item, 'path');
                return item;
            })
        }
        if (json.tabBar) {
            if (json.tabBar.list) {
                json.tabBar.list = json.tabBar.list.map(item => {
                    checkAndReplace(item, 'pagePath');
                    checkAndReplace(item, 'iconPath');
                    checkAndReplace(item, 'selectedIconPath');
                    return item;
                })
            }
            if (json.tabBar.midButton) {
                checkAndReplace(json.tabBar.midButton, 'iconPath');
            }
        }
        return JSON.stringify(json)
    }
    return jsonStr; 
}
exports.normalizePagesJson2 = normalizePagesJson2;`
        ]
      ]
    );

    fs.writeFileSync(filePath, content);
    console.log('已使每个项目单独的 pages.json 支持从当前项目根目录读取页面路径');
  }
}

function resetUniMpViteMainJs() {
  const filePath = fromDCloudIO('uni-mp-vite/dist/plugins/mainJs.js');
  let content = fs.readFileSync(filePath).toString();

  if (!content.includes('global.pagesJson = pagesJson;')) {
    content = replacesAll(
      content,
      [
        [
          `return \`\${code};createApp().app.mount("#app");\`;`,
          `return \`\${code};
      const {app} = createApp();
      global.pagesJson = pagesJson;
      app.mount("#app");\`;`
        ],
        [
          `});
                    return {
                        code: \`import '\\0plugin-vue:export-helper';import 'uni-mp-runtime';import './\${uni_cli_shared_1.PAGES_JSON_JS}';\` +
                            code,`,
          `});
                    const pagesJsPath = process.env.PROJECT_PAGES_JS.replaceAll('\\\\', '/').split('src/')[1];
                    const pagesJsonPath = process.env.PROJECT_PAGES_JSON.replaceAll('\\\\', '/').split('src/')[1];
                    return {
                        code: \`import '\\0plugin-vue:export-helper';
import 'uni-mp-runtime';
import './\${pagesJsPath}';
import pagesJson from './\${pagesJsonPath}';
\` + code,`
        ]
      ]
    );
    fs.writeFileSync(filePath, content);
    console.log('已将 pagesJson 注入到 global（小程序下可以通过 global.pagesJson 获取到页面配置）');
  }
}

function injectWatchFile() {
  const filePath = fromDCloudIO('uni-h5-vite/dist/plugins/pagesJson.js');
  let content = fs.readFileSync(filePath).toString();

  if (!content.includes('PROJECT_PAGES_JSON')) {
    content = replacesAll(
      content,
      [
        [
          `if (opts.filter(id)) {`,
          `if (opts.filter(id)) {
                    this.addWatchFile(process.env.PROJECT_PAGES_JSON);`
        ],
        [
          `import.meta.globEager('./locale/*.json')`,
          `import.meta.glob('./locale/*.json', {eager: true})`
        ],
        [
          `\${name}.rpx2px = upx2px`,
          `\${name}.rpx2px = upx2px
\${name}.env = \${JSON.stringify(['CURRENT_PROJECT', 'CURRENT_ENV', 'VITE_USER_NODE_ENV', 'UNI_STAT_TITLE_JSON', 'UNI_PLATFORM', 'UNI_COMPILER_VERSION', 'UNI_UTS_PLATFORM', 'UNI_UTS_TARGET_LANGUAGE'].reduce((env, key) => {
        if (key.endsWith('JSON')) {
          env[key] = JSON.parse(process.env[key])
        } else {
          env[key] = process.env[key]
        }
        return env
      }, {}))};`
        ]
      ]
    );

    fs.writeFileSync(filePath, content);
    console.log('已将部分环境变量注入到window.env中（仅H5可用）');
  }
}

function resetUniAppVitePagesJson() {
  const filePath = fromDCloudIO('uni-mp-vite/dist/plugins/pagesJson.js');
  let content = fs.readFileSync(filePath).toString();

  if (!content.includes('CURRENT_PROJECT')) {
    content = replacesAll(
      content,
      [
        [
          `const inputDir = process.env.UNI_INPUT_DIR;`,
          `let inputDir = process.env.UNI_INPUT_DIR;
    if (process.env.CURRENT_PROJECT) {
        inputDir = path_1.default.join(inputDir, 'projects', process.env.CURRENT_PROJECT)
    }`
        ],
        [
          `function importPageCode(pagePath) {`,
          `function importPageCode(pagePath) {
        if (process.env.CURRENT_PROJECT && !uni_cli_shared_1.isStartsWithProject(pagePath)) {
            pagePath = uni_cli_shared_1.joinProjectPath(pagePath);
        }`
        ],
        [
          `if (!opts.filter(id)) {
                    return null;
                }`,
          `if (!opts.filter(id)) {
                    return null;
                }
                code = uni_cli_shared_1.normalizePagesJson2(code);`
        ]
      ]
    );

    fs.writeFileSync(filePath, content);
    console.log('已调整pagesJson的读取路径');
  }
}

function resetCopyAndWatcher() {
  const copyFilePath = fromDCloudIO('vite-plugin-uni/dist/plugins/copy.js');
  let copyContent = fs.readFileSync(copyFilePath).toString();

  if (!copyContent.includes('CURRENT_PROJECT')) {
    copyContent = replacesAll(
      copyContent,
      [
        [
          `const assets = [staticDir, uniModulesStaticDir];`,
          `const projectStaticDir = 'projects/' + process.env.CURRENT_PROJECT + '/' + uni_cli_shared_1.PUBLIC_DIR + '/**/*';
    const assets = [staticDir, uniModulesStaticDir, projectStaticDir];`
        ]
      ]
    )
    fs.writeFileSync(copyFilePath, copyContent);
    console.log('已将 project 下的 static 目录加入到 dist copy 列表中');
  }

  const watcherFilePath = fromDCloudIO('uni-cli-shared/dist/watcher.js');
  let watcherContent = fs.readFileSync(watcherFilePath).toString();

  if (!watcherContent.includes('CURRENT_PROJECT')) {
    watcherContent = replacesAll(
      watcherContent,
      [
        [
          `return path_1.default.join(this.dest, from);`,
          `const projectToken = \`projects\\\\\${process.env.CURRENT_PROJECT}\`;
        if (from.startsWith(projectToken)) {
            from = from.replaceAll(projectToken, '');
        }
        return path_1.default.join(this.dest, from);`
        ]
      ]
    )
    fs.writeFileSync(watcherFilePath, watcherContent);
    console.log('已调整 project 下 static 的 dist copy 的输出路径');
  }
}

function resetContext() {
  const filePath = fromDCloudIO('uni-cli-shared/dist/preprocess/context.js');
  let content = fs.readFileSync(filePath).toString();

  if (!content.includes('CURRENT_PROJECT')) {
    content = replacesAll(
      content,
      [
        [
          `extend(preVueContext, defaultContext, vueContext);`,
          `if (process.env.CURRENT_PROJECT) {
        defaultContext[normalizeKey(process.env.CURRENT_PROJECT)] = true;
    }
    extend(preVueContext, defaultContext, vueContext);`
        ]
      ]
    )

    fs.writeFileSync(filePath, content);
    console.log('已调整添加项目独有的条件编译');
  }
}

function fixVueRuntimeError() {
  [
    'uni-h5-vue/dist/vue.runtime.cjs.js',
    'uni-h5-vue/dist/vue.runtime.esm.js',
  ].forEach(p => {
    const filePath = fromDCloudIO(p);
    let content = fs.readFileSync(filePath).toString();

    if (!content.includes('if (!el) return false;')) {
      content = replacesAll(
        content,
        [
          [
            `const forcePatchProp = (el, key) => {`,
            `const forcePatchProp = (el, key) => {
    if (!el) return false;`
          ]
        ]
      )

      fs.writeFileSync(filePath, content);
      console.log('修复vue runtime中的问题');
    }
  })
}

function resetH5VitePluginCss() {
  const filePath = fromDCloudIO('uni-h5-vite/dist/plugins/css.js');
  let content = fs.readFileSync(filePath).toString();

  if (content.includes(`enforce: 'pre'`)) {
    content = replacesAll(
      content,
      [
        [
          `enforce: 'pre'`,
          `order: 'pre'`
        ],
        [
          `transform()`,
          `handler()`
        ],
      ]
    )

    fs.writeFileSync(filePath, content);
    console.log('修复uni-h5-vite中的配置问题');
  }
}

function resetPagesJsonConfig() {
  const pathList = [
    fromDCloudIO('uni-app-uts/dist/plugins/android/pagesJson.js'),
    fromDCloudIO('uni-app-uts/dist/plugins/ios/pagesJson.js'),
    fromDCloudIO('uni-app-vite/dist/nvue/plugins/pagesJson.js'),
    fromDCloudIO('uni-app-vite/dist/vue/plugins/pagesJson.js'),
    fromDCloudIO('uni-mp-vite/dist/plugins/pagesJson.js'),
    fromDCloudIO('uni-cli-shared/dist/json/pages.js'),
    fromDCloudIO('uni-cli-shared/dist/vite/plugins/jsonJs.js'),
    fromDCloudIO('uni-h5-vite/dist/plugins/mainJs.js'),
    fromDCloudIO('uni-cli-shared/dist/json/manifest.js'),
    fromDCloudIO('uni-app/node_modules/@dcloudio/uni-cli-shared/dist/json/manifest.js'),
    fromDCloudIO('vite-plugin-uni/dist/configResolved/options.js'),
    fromDCloudIO('uni-h5/dist/uni-h5.es.js'),
    fromDCloudIO('uni-cli-shared/dist/vite/plugins/cssScoped.js'),
    fromDCloudIO('uni-h5-vue/dist/vue.runtime.esm.js'),
  ];

  pathList.forEach((path, index) => {
    let isChange = false;
    if (!fs.existsSync(path)) return;
    let content = fs.readFileSync(path).toString();

    if (content.includes('extend(slots, children)')) {
      content = replacesAll(
        content,
        [
          [
            `extend(slots, children);`,
            `let {_, ...children_new} = children; extend(slots, children_new);`
          ],
        ]
      )
      isChange = true;
    }

    if (content.includes(`function addScoped(code) {`) && !content.includes(`function addScoped(code) { return code }`)) {
      content = replacesAll(
        content,
        [
          [
            `function addScoped(code) {`,
            `function addScoped(code) { return code }
function addScoped8Ga(code) {`
          ],
        ]
      )
      isChange = true;
    }

    if (content.includes('size.width = rootEl.offsetWidth')) {
      content = replacesAll(
        content,
        [
          [
            'size.width = rootEl.offsetWidth',
            'size.width = rootEl?.offsetWidth'
          ],
          [
            'size.height = rootEl.offsetHeight',
            'size.height = rootEl?.offsetHeight',
          ]
        ]
      )
      isChange = true;
    }

    if (content.includes(`resolve(process.env.UNI_INPUT_DIR, 'pages.json')`)) {
      content = replaceAll(
        content,
        `path_1.default.resolve(process.env.UNI_INPUT_DIR, 'pages.json')`,
        `process.env.PROJECT_PAGES_JSON`
      );
      isChange = true;
    }

    if (content.includes(`path_1.default.join(inputDir, 'pages.json')`)) {
      content = replaceAll(
        content,
        `path_1.default.join(inputDir, 'pages.json')`,
        `process.env.PROJECT_PAGES_JSON`
      );
      isChange = true;
    }

    if (content.includes(`path_1.default.resolve(inputDir, 'pages.json')`)) {
      content = replaceAll(
        content,
        `path_1.default.resolve(inputDir, 'pages.json')`,
        `process.env.PROJECT_PAGES_JSON`
      );
      isChange = true;
    }

    if (content.includes(`jsonPath = (0, utils_1.normalizePath)(path_1.default.join(process.env.UNI_INPUT_DIR, name))`)) {
      content = replaceAll(
        content,
        `jsonPath = (0, utils_1.normalizePath)(path_1.default.join(process.env.UNI_INPUT_DIR, name));
            jsonJsPath = (0, utils_1.normalizePath)(path_1.default.join(process.env.UNI_INPUT_DIR, JSON_JS));`,
        `if (name === 'pages.json') {
                jsonPath = process.env.PROJECT_PAGES_JSON;
                jsonJsPath = process.env.PROJECT_PAGES_JS;
            } else {
                jsonPath = process.env.PROJECT_MANIFEST_JSON;
                jsonJsPath = process.env.PROJECT_MANIFEST_JS;
            }`
      );
      isChange = true;
    }

    if (content.includes(`uni_cli_shared_1.PAGES_JSON_JS`)) {
      content = replaceAll(
        content,
        `uni_cli_shared_1.PAGES_JSON_JS`,
        `process.env.PAGES_JSON_JS`
      );
      isChange = true;
    }

    if (content.includes(`path_1.default.join(inputDir, 'manifest.json')`)) {
      content = replaceAll(
        content,
        `path_1.default.join(inputDir, 'manifest.json')`,
        `process.env.PROJECT_MANIFEST_JSON`
      );
      isChange = true;
    }

    if (content.includes(`path_1.default.join(process.env.UNI_INPUT_DIR, 'manifest.json')`)) {
      content = replaceAll(
        content,
        `path_1.default.join(process.env.UNI_INPUT_DIR, 'manifest.json')`,
        `process.env.PROJECT_MANIFEST_JSON`
      );
      isChange = true;
    }

    if (isChange) {
      fs.writeFileSync(path, content);
      console.log(`已调整 ${path.split('node_modules')[1]}`);
    }
  });
}

function inject() {
  resetPlugin();
  injectAction();
  resetBuild();
  resetNormalizePagePath();
  resetUniAppVitePagesJson();
  resetUniMpViteMainJs();
  resetH5VitePluginCss(); //
  // 没有解决dev时找不到文件的问题
  // resetCopyAndWatcher();
  resetContext();
  resetPagesJsonConfig();
  fixVueRuntimeError();
  injectWatchFile();
}

exports.inject = inject;